#include "coin.h"

 Coin::Coin(std::string   name):
          m_websocketstream(),
          m_name(name)
   {
      m_websocketstream.SetPair(m_name);

      std::cout << "Constructor Coin starting..." << std::endl;
   }

 Coin::~Coin() {
     std::cout << "DeConstructor Coin starting..." << std::endl;

   }

void Coin::Show(){
     std::cout << "Coin String==" << m_name <<std::endl;
}

void Coin::GetOrder50Value(){
  m_bid50_value = 0;
  m_ask50_value = 0;

  for (const auto& element : m_bid50) {
    m_bid50_value = m_bid50_value + element.second;
  }

  for (const auto& element : m_ask50) {
    m_ask50_value = m_ask50_value + element.second;
  }
}


void Coin::ParsePublicStream(beast::flat_buffer buffer){
      json::object req_obj;
      json::value  req;
      std::string firstkey;
      std::string firstvalue;
      std::string type;
      std::array<std::string,2> ss;
      std::array< long double,2> ss1;
      std::cout << beast::make_printable(buffer.data()) << std::endl;
      // для оценки времени выполнения------------------------
      using boost::chrono::duration_cast;
      using boost::chrono::microseconds;
      typedef boost::chrono::high_resolution_clock clock;
      typedef boost::chrono::time_point <clock> time_point;
      time_point tp_start, tp_end;
      long long duration = 0;
       // ---------------------------------------------------
//----------------------------------JSON Parsing----------------------------
      auto defualt_precision{std::cout.precision()};
      setlocale(LC_NUMERIC , "C");
      tp_start = clock::now();
      std::string str = beast::buffers_to_string(buffer.data());
      boost::system::error_code errcode;
      req = json::parse(str, errcode ).as_object();
      req_obj = json::parse(str, errcode ).as_object();
        if (errcode)
          std::cout << "Parsing JSON failed: " << errcode.message() << std::endl;
      auto const& obj = req.get_object();
      auto it = obj.begin();
      firstkey = json::serialize(it->key());
          if (firstkey == R"("topic")") {
             firstvalue = json::serialize(it -> value());
                if (firstvalue == R"("orderbook.50.)" + m_name +R"(")") {
                  m_bid50_hyst.push_back(m_bid50);
                  m_ask50_hyst.push_back(m_ask50);
                  auto& data_obj = req_obj["data"].as_object();
                  m_ts50 = req_obj["ts"].as_int64();
                  m_cts50 = req_obj["cts"].as_int64();
                  m_u50 = data_obj["u"].as_int64();
                  m_seq50 = data_obj["seq"].as_int64();
                  type =  req_obj["type"].as_string();
                       if ( type == "snapshot" ) {
                          m_bid50.clear();
                          m_ask50.clear();
                            for (auto&bid:data_obj["b"].as_array()) {
                                ss[0] = bid.at(0).as_string();
                                ss[1] = bid.at(1).as_string();
                                ss1[0] = std::stold(std::move(ss[0]));
                                ss1[1] = std::stold(std::move(ss[1]));
                                m_bid50[ss1[0]] = ss1[1];
                                    }
                            for (auto&ask:data_obj["a"].as_array()) {
                                ss[0] = ask.at(0).as_string();
                                ss[1] = ask.at(1).as_string();
                                ss1[0] = std::stold(std::move(ss[0]));
                                ss1[1] = std::stold(std::move(ss[1]));
                                m_ask50[ss1[0]] = ss1[1];
                               }
                        }
                        if ( type == "delta" ) {
                            for (auto&bid:data_obj["b"].as_array()) {
                                ss[0] = bid.at(0).as_string();
                                ss[1] = bid.at(1).as_string();
                                ss1[0] = std::stold(std::move(ss[0]));
                                ss1[1] = std::stold(std::move(ss[1]));
                                  if (ss1[1] !=0 ) m_bid50[ss1[0]] = ss1[1]; else m_bid50.erase(ss1[0]);
                              }
                            for (auto&ask:data_obj["a"].as_array()) {
                                ss[0] = ask.at(0).as_string();
                                ss[1] = ask.at(1).as_string();
                                ss1[0] = std::stold(std::move(ss[0]));
                                ss1[1] = std::stold(std::move(ss[1]));
                                  if (ss1[1] !=0 ) m_ask50[ss1[0]] = ss1[1]; else m_ask50.erase(ss1[0]);
                               }

                        }
                        GetOrder50Value();
                               tp_end = clock::now();
                               duration = duration_cast <microseconds> (tp_end - tp_start).count();
                               std::cout << "Duration = " << duration << std::endl;
/*
                               for (const auto& element:test) {
                                   std::cout << "bid[0]== " << std::fixed << std::setprecision(6) << element.first << "bid[1]== " << element.second << std::endl;
                                }

                                   for (const auto& element:test1) {
                                   std::cout << "ask[0]== " << std::fixed << std::setprecision(6) << element.first << "ask[1]== " << element.second << std::endl;
                                }

*/

                                 std::cout << "Value bid=  "  << m_bid50_value << std::endl;
                                 std::cout << "Value ask=  "  << m_ask50_value << std::endl;
                                 std::cout << std::setprecision(defualt_precision);
                  }
                    if (firstvalue == R"("publicTrade.)" + m_name +R"(")") {
                                std::cout << "publicTrade." << std::endl;
                                 std::cout << str << std::endl;
                            }
            }
}

void Coin::AddPublicStream(){

    m_websocketstream.SetPtr(shared_from_this());
    m_subscription = R"({"op": "subscribe", "args": ["orderbook.50.)" + m_name + R"("]})";
    m_websocketstream.AddPublicStream(m_host, m_streamspot, m_subscription);
    m_subscription = R"({"op": "subscribe", "args": ["publicTrade.)" + m_name + R"("]})";
    m_websocketstream.AddPublicStream(m_host, m_streamspot, m_subscription);
}

void Coin::StopWebSocket(){
   m_websocketstream.StopWebSocket();
}


